#include "16s1y.h"
#ifndef ZK_USE_SPI
/* 初始化软件方式模拟SPI的IO口 */
const GPIO_Init_Param_Typedef GPIO_ZK[5] = {
    {GPIOB, {LL_GPIO_PIN_10, LL_GPIO_MODE_OUTPUT, LL_GPIO_SPEED_FREQ_HIGH, LL_GPIO_OUTPUT_PUSHPULL, 0}, 1}, // 字库片选  FLASH_CS
    {GPIOA, {LL_GPIO_PIN_5, LL_GPIO_MODE_OUTPUT, LL_GPIO_SPEED_FREQ_HIGH, LL_GPIO_OUTPUT_PUSHPULL, 0}, 0},  // 时钟      FLASH_CLK
    {GPIOA, {LL_GPIO_PIN_7, LL_GPIO_MODE_OUTPUT, LL_GPIO_SPEED_FREQ_HIGH, LL_GPIO_OUTPUT_PUSHPULL, 0}, 0},  // 送向字库   FLASH_MOSI
    {GPIOA, {LL_GPIO_PIN_4, LL_GPIO_MODE_FLOATING, 0, 0, 0}, 0},                                            // 字库输出:  FLASH_MISO
    {0, {0, 0, 0, 0, 0}, 0}};
#else
/* 初始化SPI要用到的片选口 */
const GPIO_Init_Param_Typedef GPIO_ZK[3] = {
    {GPIOB, {LL_GPIO_PIN_10, LL_GPIO_MODE_OUTPUT, LL_GPIO_SPEED_FREQ_HIGH, LL_GPIO_OUTPUT_PUSHPULL, 0}, 1}, // 字库片选  FLASH_CS
    {0, {0, 0, 0, 0, 0}, 0}};
#endif // !ZK_USE_SPI

#ifndef ZK_USE_SPI
/* 使用软件模拟 SPI 向字库写数据*/
void zk_byte_write(uint8_t cmd)
{
    for (uint8_t i = 0; i < 8; i++)
    {
        ZK_MOSI = cmd & 0x80 ? 1 : 0;
        cmd <<= 1;
        ZK_CLK = 0;
        ZK_CLK = 1;
    }
}

uint8_t zk_byte_read()
{
    uint8_t ret = 0;
    for (uint8_t i = 0; i < 8; i++)
    {
        ZK_CLK = 0;
        ret <<= 1;
        ret += ZK_MISO;
        ZK_CLK = 1;
    }
    return ret;
}

/* 使用软件模拟 SPI 从字库读数据 */
void zk_read(uint8_t *pBuff, uint8_t len)
{
    while (len--)
    {
        *pBuff++ = zk_byte_read();
    }
}

/* 使用软件模拟写 SPI */
void zk_write(uint8_t *pBuff, uint8_t len)
{
    while (len--)
    {
        zk_byte_write(*pBuff);
        pBuff++;
    }
}
#endif // !ZK_USE_SPI

void zk_init()
{
    GPIO_Init((GPIO_Init_Param_Typedef *)GPIO_ZK);
}

void zk_set_16x16_address(uint16_t text)
{
    uint32_t cmd = ZK_READ_CMD;
    uint8_t reg, pos;
    reg = (uint8_t)text;
    pos = (uint8_t)(text >> 8);
    /* 1到3区的非汉字字符 */
    if ((reg >= 0xA1) && (reg <= 0xA3))
    {
        cmd |= ((reg - 0xA1) * 94 + (pos - 0xA1)) * 32;
    }
    /* 9区的非汉字字符 */
    else if (reg == 0xA9)
    {
        cmd |= ((3 * 94) + (pos - 0xA1)) * 32;
    }
    /* 16到87区的汉字 */
    else if ((reg >= 0xB0) && (reg <= 0xF7))
    {
        cmd |= ((reg - 0xB0) * 94 + 9 * 94 + (pos - 0xA1)) * 32;
    }
    asm volatile("rev %0, %1" : "=r"(cmd) : "r"(cmd));
    zk_write((uint8_t *)&cmd, 4);
    SendDummyByte;
}

/* 获取程序内字库 */
uint8_t *zk_get_8x16_font(uint8_t text)
{
    return (uint8_t *)&ascii_8x16_font[(text - 0x20) * 16];
}

/* 获取程序内字库 */
uint8_t *zk_get_5x7_font(uint8_t text)
{
    return (uint8_t *)&ascii_5x7_font[(text - 0x20) * 8];
}

void zk_read_16x16_font(uint8_t *buf, uint16_t text)
{
    ZK_CS = 0;
    zk_set_16x16_address(text);
    zk_read(buf, 32);
    ZK_CS = 1;
}

void zk_read_8x16_font(uint8_t *buf, uint8_t text)
{
    uint8_t *psrc = (uint8_t *)&ascii_8x16_font[(text - 0x20) * 16];
    for (uint8_t n = 0; n < 16; n++)
    {
        *buf++ = *psrc++;
    }
}

void zk_read_5x7_font(uint8_t *buf, uint8_t text)
{
    uint8_t *psrc = (uint8_t *)&ascii_5x7_font[(text - 0x20) * 8];
    for (uint8_t n = 0; n < 8; n++)
    {
        *buf++ = *psrc++;
    }
}

/* 字库的竖直转换为水平 */
void zk_V2H_16x16_font(uint8_t *buf)
{
    zk_V2H_16x8_font(buf);
    zk_V2H_16x8_font(buf + 16);
}

void zk_V2H_16x8_font(uint8_t *buf)
{
    uint8_t left[8] = {0};
    uint8_t right[8] = {0};

    for (uint8_t j = 0; j < 8; j++)
    {
        for (uint8_t i = 0; i < 8; i++)
        {
            left[j] |= ((buf[i] & 0x01) << i); // 0-7字节取出最低位放在最低位
            buf[i] >>= 1;                      // 右移一位,继续取
        }
    }
    for (uint8_t j = 0; j < 8; j++)
    {
        for (uint8_t i = 0; i < 8; i++)
        {
            right[j] |= ((buf[i + 8] & 0x01) << i);
            buf[i + 8] >>= 1;
        }
    }
    for (uint8_t n = 0; n < 8; n++)
    {
        buf[n * 2] = left[n];
        buf[n * 2 + 1] = right[n];
    }
}